#include "Application.h"
#include "Window.h"

using namespace GUIToolkit;

Application Application::app;

event Application::OnRun;
event Application::OnIdle;
event Application::OnExit;

Application::Application()
{
	GdiplusStartupInput gdiplusStartupInput;
	::GdiplusStartup(&token, &gdiplusStartupInput, NULL);
}

Application::~Application()
{
	::GdiplusShutdown(token);
}

int Application::Run(Window* main)
{
	app.main = main;
	HWND mainhwnd = main ? main->GetHandle() : NULL;

	OnRun(main);

	MSG msg;
	ZeroMemory( &msg, sizeof(msg) );

	while( msg.message != WM_QUIT )
	{
		if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
		{
			if(msg.hwnd == NULL && msg.message == WM_NULL)
			{
				HWND hWnd = (HWND)msg.wParam;
				Window* win = (Window*)msg.lParam;
				if( win != NULL)
				{
					if(win->GetHandle() == hWnd)
						app.windows[hWnd] = win;
				}
				else
				{
					win = app.windows[hWnd];
					app.windows.erase(hWnd);
					if(app.focus == win) app.focus = NULL;
					SafeRelease(win);
					if(mainhwnd == hWnd || app.windows.empty()) Application::Exit();
				}
			}

			if(msg.message == WM_KILLFOCUS )
			{
				SetFocus(NULL);
			}
			else if(msg.message == WM_SETFOCUS)
			{
				auto it = app.windows.find(msg.hwnd);
				if( it != app.windows.end())
					SetFocus(it->second);
				else
					SetFocus(NULL);
			}

			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			OnIdle(NULL);
			::WaitMessage();
		}
	}
	
	while(app.windows.size() > 0)
		delete app.windows.begin()->second;

	app.main = NULL;
	app.focus = NULL;

	OnExit(NULL);

	return 0;
}

Control* Application::GetFocus()
{
	return app.focus;
}

void Application::SetFocus(Control* ui) 
{
	auto temp = app.focus;
	if(ui != NULL && ui->Focusable())
		app.focus = ui;

	if( temp != NULL )
		temp->HandleMessage(MESSAGE::MSG_FOCUS, (void*)FALSE);
	if(app.focus != NULL)
		app.focus->HandleMessage(MESSAGE::MSG_FOCUS, (void*)TRUE);
}

void Application::Exit()
{
	::PostQuitMessage( 0 );
}

